package mixlog

import (
	"fmt"
	"os"
)

// MixLog 日志记录器
type MixLog struct {
	// RuntimeCallerSkip 运行 `runtime.Caller` 跳过的堆栈数量，用于获取调用者的函数名和文件名
	RuntimeCallerSkip int

	// handlers 记录日志的 handler
	handlers []*handler

	// runtimeCallerOff 通过 `runtime.Caller` 获取函数名和文件名的开关，添加handler的时候自动设置。
	// 只有有一个 handler 的 formatter 包含了函数名、文件名、文件行号，就自动设置为 false
	runtimeCallerOff bool

	// lvl 设置为 handlers 中最小的一个级别，添加handler的时候自动设置
	lvl Lvl
}

// NewMixLog 创建一个日志记录器实例
func NewMixLog(handlers ...*handler) *MixLog {
	m := &MixLog{RuntimeCallerSkip: 3}
	m.SetHandler(handlers...)
	return m
}

// AddHandler 添加handler
func (m *MixLog) SetHandler(handlers ...*handler) {
	m.lvl = LvlFatal
	m.runtimeCallerOff = true
	m.handlers = make([]*handler, 0, len(handlers))

	for _, h := range handlers {
		m.handlers = append(m.handlers, h)
		if h.Lvl < m.lvl {
			m.lvl = h.Lvl
		}

		if h.Formatter.needRuntimeCaller {
			m.runtimeCallerOff = false
		}
	}
}

// writeLog 将日志写入handler
func (m *MixLog) writeLog(lvl Lvl, format string, a ...interface{}) {
	if lvl >= m.lvl {
		entry := newEntry(lvl, fmt.Sprintf(format+"\n", a...), m.runtimeCallerOff, m.RuntimeCallerSkip)
		for _, h := range m.handlers {
			h.writeLog(entry)
		}
	}
}

func (m *MixLog) Debug(a ...interface{})   { m.writeLog(LvlDebug, fmt.Sprint(a...)) }
func (m *MixLog) Info(a ...interface{})    { m.writeLog(LvlInfo, fmt.Sprint(a...)) }
func (m *MixLog) Warning(a ...interface{}) { m.writeLog(LvlWarning, fmt.Sprint(a...)) }
func (m *MixLog) Error(a ...interface{})   { m.writeLog(LvlError, fmt.Sprint(a...)) }
func (m *MixLog) Fatal(a ...interface{}) {
	m.writeLog(LvlFatal, fmt.Sprint(a...))
	os.Exit(1)
}

func (m *MixLog) Debugf(format string, a ...interface{})   { m.writeLog(LvlDebug, format, a...) }
func (m *MixLog) Infof(format string, a ...interface{})    { m.writeLog(LvlInfo, format, a...) }
func (m *MixLog) Warningf(format string, a ...interface{}) { m.writeLog(LvlWarning, format, a...) }
func (m *MixLog) Errorf(format string, a ...interface{})   { m.writeLog(LvlError, format, a...) }
func (m *MixLog) Fatalf(format string, a ...interface{}) {
	m.writeLog(LvlFatal, format, a...)
	os.Exit(1)
}
